package com.cj.park_dispatch.http;

import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.Charset;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import okio.Buffer;
import retrofit2.Converter;
import retrofit2.Retrofit;

import static kotlin.text.Charsets.UTF_8;

//import static okhttp3.internal.Util.UTF_8;

/**
 * 统一处理服务器返回来的错误信息
 *
 * @author zengyi
 * create at 2017/1/16 17:27
 */

public class CustomGsonConverterFactory extends Converter.Factory {
	private final Gson gson;

	private CustomGsonConverterFactory(Gson gson) {
		if (gson == null) {
			throw new NullPointerException("gson == null");
		}
		this.gson = gson;
	}

	public static CustomGsonConverterFactory create() {
		return create(new Gson());
	}

	public static CustomGsonConverterFactory create(Gson gson) {
		return new CustomGsonConverterFactory(gson);
	}

	@Override
	public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
		TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
		return new CustomGsonResponseBodyConverter<>(gson, adapter);
	}

	@Override
	public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
		TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
		return new CustomGsonRequestBodyConverter<>(gson, adapter);
	}

	//CustomGsonRequestBodyConverter.java
	static final class CustomGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
		private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
		private static final Charset UTF_8 = Charset.forName("UTF-8");
		private final Gson gson;
		private final TypeAdapter<T> adapter;

		CustomGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
			this.gson = gson;
			this.adapter = adapter;
		}

		@Override
		public RequestBody convert(T value) throws IOException {
			Buffer buffer = new Buffer();
			Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
			JsonWriter jsonWriter = gson.newJsonWriter(writer);
			adapter.write(jsonWriter, value);
			jsonWriter.close();
			return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
		}
	}

	//CustomGsonResponseBodyConverter.java
	final class CustomGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
		private final Gson gson;
		private final TypeAdapter<T> adapter;

		CustomGsonResponseBodyConverter(Gson gson, TypeAdapter<T> adapter) {
			this.gson = gson;
			this.adapter = adapter;
		}

		@Override
		public T convert(ResponseBody value) throws IOException {
			try {
				String response = value.string();
				BaseResult baseResult = gson.fromJson(response, BaseResult.class);
				if (baseResult.getCode() == 200) {
					MediaType contentType = value.contentType();
					Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
					InputStream inputStream = new ByteArrayInputStream(response.getBytes());
					Reader reader = new InputStreamReader(inputStream, charset);
					JsonReader jsonReader = gson.newJsonReader(reader);
					return adapter.read(jsonReader);
				} else {
					value.close();
					throw new HttpTimeException(baseResult.getMsg());
				}

			} finally {
				value.close();
			}

		}
	}
}
